<?php
/**
 * @package PWE.controler
 * @author Gmax <gmaxfr78@gmail.com>
 */
class controler_upload extends controler{    
    private $_error = array();
    private $_absRep;
    private $_prefix;
    private $_rep;
    
    private $_tmpDir;
    private $_tmpName;
    
    private $_origineName;
    private $_ext;
    private $_type;
    private $_absPath;
    
    private $_width = 0;
    private $_height = 0;
    
    private $_documentExtension = array('pdf','xls','csv','txt','doc','docx');
    private $_imageExtension = array('jpg','gif','png','tif');
    
    /**
     * initialise un uploder de fichier
     * @param string $rep dossier cible
     * @param string $prefix chemin vers la cible depuis le point d'instanciation
     */
    function __construct($rep='uploads/',$prefix='') {
        $this->_absRep = $rep;
        $this->_prefix = $prefix;
        $this->_rep = $prefix.$rep;
    }
    
    /**
     * renvoi le type de fichier uploadé
     * @return string
     */
    public function getFileType(){
        return $this->_type;
    }
    /**
     * renvoi le chemin vers le fichier
     * @param boolean $absolute chemin absolu, default true
     * @return string
     */
    public function getPath($absolute = true){
        if(!$absolute) return $this->_prefix.$this->_absPath;
        return $this->_absPath;
    }
    /**
     * renvoi la largeur de l'image uploadé
     * @return number
     */
    public function getWidth(){
        return $this->_width+0;
    }
    /**
     * renvoi la hauteur de l'image uploadé
     * @return number
     */
    public function getHeight(){
        return $this->_height+0;
    }
    /**
     * renvoi la liste des erreurs rencontrées
     * @return string
     */
    public function getErrorMessage(){
        return implode("\n\r",$this->_error);
    }
    
    /**
     * entrée générale de l'uploader : rootage selon type de fichier
     * @param string $file chemin temporaire de l'upload $_FILES[file_field][tmp_name]
     * @param string $origineFileName nom d'origine du fichier
     * @param array $typeByExtension tableau de limitation d'extensions autorisées (sans le .)
     * @return boolean
     */
    public function uploadFile($file,$origineFileName,$typeByExtension=array()){
        $this->_error = array();
        $result = false;
        
        $this->_cleanTmpDir();
        
        if(is_uploaded_file($file)){
            $this->_origineName = $origineFileName;
            $this->_ext = $this->getFileExtension($this->_origineName);
            $this->_type = $this->getTypeFileByExtension($this->_ext);
            
            if($this->_type==='image'){
                return $this->_uploadImage($file, $typeByExtension);
            }elseif($this->_type==='document'){
                return $this->_uploadDocument($file, $typeByExtension);
            }else{
                $this->_error[] = "Ce format de fichier n'est pas valide : .".$this->_ext;
            }
        }else{
            $this->_error[] = "La source n'est pas un fichier upload.";
        }
        
        return false;
    }
    /**
     * 
     * charge un fichier du serveur
     * @param string $file chemin d'acces du fichier sur le serveur
     * @param string $origineFileName nom du fichier
     * @param array $typeByExtension tableau de limitation d'extensions autorisées (sans le .)
     * @return boolean
     */
    public function loadFile($file,$origineFileName,$typeByExtension=array()){
        $this->_origineName = $origineFileName;
        $this->_ext = $this->getFileExtension($this->_origineName);
        $this->_type = $this->getTypeFileByExtension($this->_ext);
        if($this->_type==='image'){
            return $this->_loadImage($file, $typeByExtension);
        }elseif($this->_type==='document'){
            return $this->_loadDocument($file, $typeByExtension);
        }else{
            $this->_error[] = "Ce format de fichier n'est pas valide : .".$this->_ext;
        }
        
        return false;
    }


    /**
     * enregistre le fichier à son emplacement définitif selon le nom choisi
     * @param string $fileName
     * @return boolean
     */
    public function saveFile($newFileName='',$sousDossier=''){
        $source = $this->_tmpDir.$this->_tmpName;
        if($newFileName!==''){
            if(strripos($newFileName, '.')!==false){
                $name = substr($newFileName, 0, strripos($newFileName, '.')).'.'.$this->_ext;
            }else{
                $name = $newFileName.'.'.$this->_ext;
            }
        }else{
            $name = $this->_origineName;
        }
        
        $target = $this->_getDestination($name, $sousDossier);
        
        $result = rename($source, $target);
        
        if(!$result){
            $this->_error[] = "Le fichier n'a pas pu être déplacé.";
        }else{
            chmod($target,0755);
        }
        return $result;
    }
    
    /**
     * renvoi un nom de fichier unique en vérifiant qu'il n'existe pas déjà à l'emplacement indiqué
     * @param string $path
     * @param string $fileName
     * @param string $ext
     * @return string
     */
    public function getUniqueFileName($path,$fileName,$ext){
        if(file_exists($path.$fileName.'.'.$ext)){
            $do = true;
            $i = 1;
            while($do){
                $test = $path.$fileName.'('.$i.').'.$ext;
                if(!file_exists($test)){
                    $do = false;
                    $fileName = $fileName.'('.$i.')';
                }else{
                    $i++;
                }
            }
        }
        return $fileName;
    }
    
    /**
     * retour le type imoge ou document déduit de l'extension de fichier
     * @param string $ext
     * @return string
     */
    public function getTypeFileByExtension($ext){
        if($this->_checkValideExtension($ext, 'image')){
            return 'image';
        }elseif($this->_checkValideExtension($ext, 'document')){
            return 'document';
        }else{
            return '';
        }
    }

    /**
     * renvoi l'extension de fichier
     * @param string $fileName
     * @return string
     */
    public function getFileExtension($fileName){
        $ext = strtolower(substr($fileName,strripos($fileName,'.')+1));
        return ($ext!=='')?$this->_mapExtension($ext):'';
    }
    
    /**
     * redimentionne l'image uploadée
     * @param int $maxWidth
     * @param int $maxHeight
     */
    public function resizeImage($maxWidth=0,$maxHeight=0,$startX = 0,$startY = 0, $cropWidth = 0, $cropHeight = 0){
        $resize = false;
        
        $startWidth = $newWidth = $this->_width;
        $startHeight = $newHeight = $this->_height;
        
        if($cropWidth>0&&$cropHeight>0&&($cropWidth!=$startWidth||$cropHeight!=$startHeight)){
            $resize = true;
            $startWidth = $newWidth = $cropWidth;
            $startHeight = $newHeight = $cropHeight;
        }
        
        if($newWidth>0 && $maxWidth>0 && $newWidth>$maxWidth){
            $resize = true;
            $scale = $maxWidth/$newWidth;
            $newWidth = $maxWidth;
            $newHeight = ceil($newHeight*$scale);
        }
        
        if($newHeight>0 && $maxHeight>0 && $newHeight>$maxHeight){
            $resize = true;
            $scale = $maxHeight/$newHeight;
            $newHeight = $maxHeight;
            $newWidth = ceil($newWidth*$scale);
        }
                
        if($resize){
            $image = $this->_tmpDir.$this->_tmpName;
            switch($this->_ext){
                case "gif":
                    $source=imagecreatefromgif($image); 
                    break;
                case "jpg":
                    $source=imagecreatefromjpeg($image); 
                    break;
                case "png":
                    $source=imagecreatefrompng($image); 
                    break;
            }
            $resizedImage = imagecreatetruecolor($newWidth,$newHeight);
            //imagecopyresampled($resizedImage,$source,0,0,$startX,$startY,$newWidth,$newHeight,$startWidth,$startHeight);
            switch($this->_ext){
                case "gif":
                    //transparence
                    imagecolortransparent($resizedImage, imagecolorallocatealpha($resizedImage, 0, 0, 0, 127));
                    imagealphablending($resizedImage, false);
                    imagesavealpha($resizedImage, true);
                    
                    imagecopyresampled($resizedImage,$source,0,0,$startX,$startY,$newWidth,$newHeight,$startWidth,$startHeight);
                    imagegif($resizedImage,$image); 
                    break;
                case "jpg":
                    imagecopyresampled($resizedImage,$source,0,0,$startX,$startY,$newWidth,$newHeight,$startWidth,$startHeight);
                    imagejpeg($resizedImage,$image,80); 
                    break;
                case "png":
                    //transparence
                    imagecolortransparent($resizedImage, imagecolorallocatealpha($resizedImage, 0, 0, 0, 127));
                    imagealphablending($resizedImage, false);
                    imagesavealpha($resizedImage, true);
                    
                    imagecopyresampled($resizedImage,$source,0,0,$startX,$startY,$newWidth,$newHeight,$startWidth,$startHeight);
                    imagepng($resizedImage,$image); 
                    break;
            }
            $this->_width = $newWidth;
            $this->_height = $newHeight;
            imagedestroy($resizedImage);
        }
    }
    
    /* private methodes */
    
    /**
     * upload de fichier document
     * @param type $file
     * @param type $typeByExtension
     * @return boolean
     */
    private function _uploadDocument($file,$typeByExtension=array()){
        $result = false;
        
        if(count($typeByExtension)>0){ // verification de l'extension spécifique
            if(!in_array($this->_ext, $typeByExtension)){
                $this->_error[] = "Ce format n'est pas autorisé : uniquement ".implode(' ',$typeByExtension).".";
                return false;
            }
        }
        $this->_tmpDir = $this->_getDirPath('tmp',$this->_absRep,$this->_prefix);
        $this->_tmpName = time().'.'.$this->_ext;
        $result = move_uploaded_file($file, $this->_tmpDir.$this->_tmpName); // deplacer le fichier vers la zone temporaire

        if(!$result){
            $this->_error[] = "Le fichier na pas pu être déplacé.";
        }
        
        return $result;
    }
    
    /**
     * copie de fichier document
     * @param type $file
     * @param type $typeByExtension
     * @return boolean
     */
    private function _loadDocument($file,$typeByExtension=array()){
        if(count($typeByExtension)>0){ // verification de l'extension spécifique
            if(!in_array($this->_ext, $typeByExtension)){
                $this->_error[] = "Ce format n'est pas autorisé : uniquement ".implode(' ',$typeByExtension).".";
                return false;
            }
        }
        $this->_tmpDir = $this->_getDirPath('tmp',$this->_absRep,$this->_prefix);
        $this->_tmpName = time().'.'.$this->_ext;
        $result = copy($file, $this->_tmpDir.$this->_tmpName); // deplacer le fichier vers la zone temporaire

        if(!$result){
            $this->_error[] = "Le fichier na pas pu être déplacé.";
        }
        
        return $result;
    }
    
    /**
     * upload de fichier image
     * @param string $file
     * @param array $typeByExtension
     * @return boolean
     */
    private function _uploadImage($file,$typeByExtension=array()){
        $result = false;
        
        $datas = getimagesize($file);
        if($datas[0]>0&&$datas[1]>0){
            $type = $datas[2];
            $this->_ext = $this->_mapExtension(strtolower(image_type_to_extension($type,false)));
            if(count($typeByExtension)>0){ // verification de l'extension spécifique
                if(!in_array($this->_ext, $typeByExtension)){
                    $this->_error[] = "Ce format d'image n'est pas autorisé : uniquement ".implode(' ',$typeByExtension).".";
                    return false;
                }
            }
            $this->_tmpDir = $this->_getDirPath('tmp',$this->_absRep,$this->_prefix);
            $this->_tmpName = time().'.'.$this->_ext;
            $result = move_uploaded_file($file, $this->_tmpDir.$this->_tmpName); // deplacer le fichier vers la zone temporaire
            
            $this->_width = $datas[0];
            $this->_height = $datas[1];
            
            if(!$result){
                $this->_error[] = "Le fichier na pas pu être déplacé.";
            }
        }else{
            $this->_error[] = "Le fichier n'est pas une image ou une image vide.";
        }
        return $result;
    }
    
    /**
     * copy de fichier image
     * @param string $file
     * @param array $typeByExtension
     * @return boolean
     */
    private function _loadImage($file,$typeByExtension=array()){
        $result = false;
        
        $datas = getimagesize($file);
        if($datas[0]>0&&$datas[1]>0){
            $type = $datas[2];
            $this->_ext = $this->_mapExtension(strtolower(image_type_to_extension($type,false)));
            if(count($typeByExtension)>0){ // verification de l'extension spécifique
                if(!in_array($this->_ext, $typeByExtension)){
                    $this->_error[] = "Ce format d'image n'est pas autorisé : uniquement ".implode(' ',$typeByExtension).".";
                    return false;
                }
            }
            $this->_tmpDir = $this->_getDirPath('tmp',$this->_absRep,$this->_prefix);
            $this->_tmpName = time().'.'.$this->_ext;
            $result = copy($file, $this->_tmpDir.$this->_tmpName); // deplacer le fichier vers la zone temporaire
            
            $this->_width = $datas[0];
            $this->_height = $datas[1];
            
            if(!$result){
                $this->_error[] = "Le fichier na pas pu être déplacé.";
            }
        }else{
            $this->_error[] = "Le fichier n'est pas une image ou une image vide.";
        }
        return $result;
    }
    
    /**
     * indique si l'extension de fichier est autorisée
     * @param string $ext
     * @param string $type
     * @return boolean
     */
    private function _checkValideExtension($ext,$type=''){
        $retour = false;
        if($type==='image' || $type === ''){
            $retour = in_array($ext, $this->_imageExtension);
        }
        if(!$retour && ($type==='document' || $type === '')){
            $retour = in_array($ext, $this->_documentExtension);
        }
        
        return $retour;
    }
    
    /**
     * renvoi le chemin cible en fonction du filename avec detection des doublons
     * @param string $fileName
     * @return string
     */
    private function _getDestination($fileName,$sousDossier=''){
        $fileName = substr($fileName, 0,strripos($fileName, '.'));
        $cleanedFileName = tools_convert::slug($fileName);
        
        $sousDossier = tools_convert::slug($sousDossier);
        
        $dossier = $this->_getDirPath($sousDossier,$this->_absRep,$this->_prefix);
        $fileName = $this->getUniqueFileName($dossier,$cleanedFileName,$this->_ext);
        $dest = $dossier.$fileName.'.'.$this->_ext;
        
        $this->_absPath = str_replace($this->_prefix, '', $dest);
        return $dest;
    }
    
    /**
     * renvoi le chemin vers un dossier, le dossier est créé s'il n'existe pas
     * @param string $dirName
     * @param string $path
     * @param string $prefix
     * @return string
     */
    private function _getDirPath($dirName='tmp', $path = '/',$prefix=''){
        $target = $path.$dirName;
        $hierarchie = $prefix;
        foreach(explode('/',$target) as $dir){
            if($dir!==''&&!is_dir($hierarchie.$dir)){
                if(!mkdir($hierarchie.$dir,0755)){
                    $this->_error[] = "Le dossier cible n'a pas pu être créé.";
                    break;
                }
            }
            $hierarchie .= $dir.'/';
        }
        return $hierarchie;
    }
    
    private function _cleanTmpDir(){
        $tmpDir = $this->_getDirPath('tmp',$this->_absRep,$this->_prefix);
        $limit = time()-(60*60*2); // fichiers créés il y a plus de deux heures
        if($handle = opendir($tmpDir)){
            while (false !== ($entry = readdir($handle))) {
                if ($entry != "." && $entry != ".." && is_file($tmpDir.$entry)) {
                    $name = substr($entry,0,strrpos($entry, '.'))+0;
                    if($name<$limit){
                        unlink($tmpDir.$entry);
                    }
                }
            }
            closedir($handle);
        }
    }
    
    /**
     * converti les nom d'extension spécifique en générique le cas échéant
     * @param string $ext
     * @return string
     */
    private function _mapExtension($ext){
        switch($ext){
            case 'jpeg':
            case 'pjpeg':{
                return 'jpg';
            }
            case 'tiff':{
                return 'tif';
            }
        }
        return $ext;
    }
}
?>
